iT邦幫忙

2023 iThome 鐵人賽

DAY 17
0
自我挑戰組

chatGPT 帶你從零開始寫 websocket 連線遊戲系列 第 17

D17 繼續討論 - 從遊戲循環到狀態機的演進

  • 分享至 

  • xImage
  •  

今天算是 D15 那篇之後繼續衍生的內容,因為範疇有點大,感覺還是要再好好探索一下。另外這次為了要彌補 D10 沒有程式碼可看的缺憾,所以繼續凹 chatGPT 提供範例給大家看。

平凡的遊戲循環範例 (python)

class GameBox:
    def __init__(self):
        # 初始化遊戲內部狀態
        self.game_state = {}
        self.is_playing = False

    def start_game(self):
        # 開始遊戲
        self.is_playing = True
        self.initialize_game_state()

    def initialize_game_state(self):
        # 初始化遊戲內部狀態的函數
        pass

    def process_input(self, player_input):
        # 處理玩家的輸入,這里可以根據玩家的輸入更新遊戲狀態
        if self.is_playing:
            # 根據玩家輸入更新內部狀態
            pass

    def update_game(self):
        # 更新遊戲狀態的函數,可以處理物理模擬、敵人AI等
        if self.is_playing:
            # 更新內部狀態
            pass

    def render(self):
        # 渲染遊戲內容,將內部狀態呈現給玩家
        if self.is_playing:
            # 使用渲染函數呈現遊戲內容
            pass

    def stop_game(self):
        # 結束遊戲
        self.is_playing = False
        self.cleanup_game_state()

    def cleanup_game_state(self):
        # 清理遊戲內部狀態的函數
        pass

# 創建一個遊戲實例
my_game = GameBox()

# 開始遊戲
my_game.start_game()

# 遊戲循環
while my_game.is_playing:
    player_input = get_player_input()  # 獲取玩家輸入
    my_game.process_input(player_input)  # 處理輸入
    my_game.update_game()  # 更新遊戲狀態
    my_game.render()  # 渲染遊戲內容

# 結束遊戲
my_game.stop_game()

事件驅動的遊戲循環 - 單機版 (javascript)

class GameBox {
    constructor() {
        this.gameState = {};
        this.isPlaying = false;

        // 添加事件監聽器
        document.addEventListener('gameStart', () => this.startGame());
        document.addEventListener('gameInput', (event) => this.processInput(event.detail));
        document.addEventListener('gameUpdate', () => this.updateGame());
        document.addEventListener('gameRender', () => this.render());
        document.addEventListener('gameStop', () => this.stopGame());
    }

    startGame() {
        this.isPlaying = true;
        this.initializeGameState();
    }

    initializeGameState() {
        // 初始化遊戲內部狀態的函數
    }

    processInput(playerInput) {
        if (this.isPlaying) {
            // 根據玩家輸入更新內部狀態
        }
    }

    updateGame() {
        if (this.isPlaying) {
            // 更新遊戲狀態的函數
        }
    }

    render() {
        if (this.isPlaying) {
            // 使用渲染函數呈現遊戲內容
        }
    }

    stopGame() {
        this.isPlaying = false;
        this.cleanupGameState();
    }

    cleanupGameState() {
        // 清理遊戲內部狀態的函數
    }
}

// 創建一個遊戲實例
const myGame = new GameBox();

// 觸發開始遊戲事件
const startGameEvent = new Event('gameStart');
document.dispatchEvent(startGameEvent);

// 遊戲循環
function gameLoop() {
    if (myGame.isPlaying) {
        const playerInput = getPlayerInput(); // 獲取玩家輸入
        const inputEvent = new CustomEvent('gameInput', { detail: playerInput });
        document.dispatchEvent(inputEvent);

        const updateEvent = new Event('gameUpdate');
        document.dispatchEvent(updateEvent);

        const renderEvent = new Event('gameRender');
        document.dispatchEvent(renderEvent);

        requestAnimationFrame(gameLoop); // 遞歸呼叫遊戲循環
    }
}

gameLoop(); // 開始遊戲循環

// 觸發結束遊戲事件
const stopGameEvent = new Event('gameStop');
document.dispatchEvent(stopGameEvent);

// 模擬玩家輸入的函數
function getPlayerInput() {
    // 在實際遊戲中,根據玩家的操作返回對應的輸入
    // 這里僅作為示例,返回一個隨機數字
    return Math.random();
}

事件驅動的遊戲循環 - 聯機版 (javascript)

const WebSocket = require('ws');

const ws = new WebSocket('ws://localhost:8080');

ws.on('open', () => {
    console.log('已連接到遊戲伺服器');

    // 在這里初始化客戶端,設定玩家控制元素等
});

ws.on('message', (message) => {
    const data = JSON.parse(message);

    // 根據伺服器發送的消息類型處理遊戲狀態或其他事件
    switch (data.type) {
        case 'playerId':
            const playerId = data.playerId;
            // 在這里處理獲取到的玩家ID
            break;
        case 'gameState':
            const gameState = data.gameState;
            // 在這里處理遊戲狀態,更新畫面等
            break;
        // 添加其他事件處理
    }
});

// 處理玩家輸入的函數
function sendPlayerInput(inputData) {
    // 在這里處理玩家的輸入,例如移動、攻擊等
    const message = JSON.stringify({ type: 'playerInput', inputData });
    ws.send(message);
}

// 在適當的時候呼叫 sendPlayerInput 函數以發送玩家輸入

詳細說明

昨天了解事件溯源的概念,發現「事件」跟我想像的不太一樣,所以把注意力拉回遊戲循環和狀態機這部分。一開始請 chatGPT 給出初始版本的遊戲循環,然後逐步調整為 javascript 版本 (因為到時候預計在網頁上玩),然後再擴充成多人連線版本,所以需要透過連線的機制去更新遊戲,就會有 API, broadcast 之類的要素加進來。

當然遊戲邏輯還是很複雜,但至少我們有一個好的地基,往上蓋東西比較穩


上一篇
D16 探索事件溯源 - 以簡易的井字遊戲為例
下一篇
D18 拼裝計畫 - gameLoop 和 websocket
系列文
chatGPT 帶你從零開始寫 websocket 連線遊戲31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言